iT邦幫忙

2026 iThome 鐵人賽

DAY 8
0
Kubernetes

不是背 YAML!30 天從零打造 Kubernetes 微服務:從本機實戰一路到 CKA系列 第 8

Day 8|Rolling Update 與 Rollback:Kubernetes 怎麼做到不中斷更新?

  • 分享至 

  • xImage
  •  

大家好!來到 Day 8啦
今天要跟大家談的是 要怎麼做到不中斷的去更新。

假設 API 有三個 Pod:

v1
v1
v1

現在要改上:

v2

最暴力的方法:

把三個 v1 全殺掉
再建立三個 v2

結果:

中間一段時間
沒有任何 API。
(這就是允許系統會暫時壞掉的情況)

這就是 Deployment Rolling Update 要解決的事情。


先查看目前 Image

kubectl get deployment api \
  -n cka-lab \
  -o jsonpath='{.spec.template.spec.containers[0].image}'

如果前面沿用:

nginx:alpine

現在更新:

kubectl set image \
  deployment/api \
  nginx=nginx:1.27-alpine \
  -n cka-lab

注意 nginx= 前面的 nginx 是:

Container Name

不是 Deployment Name。

https://ithelp.ithome.com.tw/upload/images/20260907/20168537iRYynITZF9.png


觀察 Rollout

kubectl rollout status \
  deployment/api \
  -n cka-lab

https://ithelp.ithome.com.tw/upload/images/20260907/20168537IMQvYa4BIj.png

同時另一個 Terminal:

kubectl get pods -n cka-lab -w

-w

Watch。

你會看到舊 Pod 與新 Pod 有一段時間同時存在。

https://ithelp.ithome.com.tw/upload/images/20260907/20168537HNptYhbiiJ.png


為什麼多一個 ReplicaSet?

kubectl get rs -n cka-lab

現在很可能看到:

舊 ReplicaSet
新 ReplicaSet

因為 Deployment 的 Pod Template 改變了。

因此:

Deployment
├── Old ReplicaSet → v1
└── New ReplicaSet → v2

新的 ReplicaSet 慢慢 Scale Up。

舊的慢慢 Scale Down。

這就是 Rolling Update。


Rollout History

kubectl rollout history \
  deployment/api \
  -n cka-lab

可以查看 Revision。
https://ithelp.ithome.com.tw/upload/images/20260907/20168537BgzYykH0Rb.png

如果 Deployment YAML 有:

kubernetes.io/change-cause

等資訊,也能更容易辨識版本。


故意部署錯誤 Image

現在我們故意做:

kubectl set image \
  deployment/api \
  nginx=nginx:this-version-does-not-exist \
  -n cka-lab

https://ithelp.ithome.com.tw/upload/images/20260907/20168537KALuxZ0sIn.png

看看:

kubectl get pods -n cka-lab

會看到:

ImagePullBackOff

https://ithelp.ithome.com.tw/upload/images/20260907/20168537P3cWd6q0R6.png

這是我們第一次故意製造真正的 Kubernetes 問題。


不要立刻修,先查

kubectl describe pod <BROKEN_POD的名字> -n cka-lab

找到 Events。

你會看到類似:

Failed to pull image

https://ithelp.ithome.com.tw/upload/images/20260907/20168537LJm9WM5qkC.png

這時我們才知道:

不是 Application Crash
不是 Probe
不是 Network

而是:

Image 根本抓不到。

Rollback

kubectl rollout undo \
  deployment/api \
  -n cka-lab
  • 第一個指令 (kubectl rollout undo):
    • 作用: 它是「下達修改指示」。它只是通知 Kubernetes API Server:「把這個 Deployment 的 Pod Template 規格換回上一個版本(Revision)的 ReplicaSet」。
    • 狀態: API Server 接收指令、寫入 etcd 後,指令就會立刻返回。這時 Deployment Controller 才剛要開始建立舊版 Pod、並逐漸終止新版 Pod。
    • 結果: 指令退出的那一秒,Pod 可能還在拉映像檔(ContainerCreating)或還沒通過健康檢查,滾動更新尚未真正完畢

https://ithelp.ithome.com.tw/upload/images/20260907/20168537APc43LoUmC.png

接著:

kubectl rollout status \
  deployment/api \
  -n cka-lab
  • 第二個指令 (kubectl rollout status):
    • 作用: 它是「阻塞並持續監控進度(Block & Watch)」。它會掛在那裡即時印出滾動進度,直到所有舊版 Pod 啟動成功、健康檢查通過,且新版 Pod 完全下線。
    • 價值:
      • 人工操作時: 確認不是指令敲完就沒事,確保服務真的順利起死回生(避免上一版也有問題導致全部 CrashLoopBackOff)。
      • CI/CD 自動化腳本中: status 指令會卡住執行緒,若成功退出狀態碼為 0;若超時或失敗會報錯退出,讓自動化流程能捕捉到錯誤。

核心結論: 第一個指令已經完成 rollback 的宣告;第二個指令是為了「確定它順利跑完了」,而不是觸發 rollback 的必要條件。

https://ithelp.ithome.com.tw/upload/images/20260907/20168537l8lEY86mhH.png

Deployment 回到上一個 Revision。

這就是:

Rollback。

但其實這個做法在實務上已經沒有很常用?存在著更好的做法

在現代生產環境(Production)中,kubectl rollout undo 已經不太常作為常規手段使用,甚至被多數團隊視為「緊急避難用的反模式(Anti-pattern)」。

但在兩種情境依然常用:

  1. 認證考試(如 CKA/CKAD): 這是必考的高頻基本操作。
  2. P0/P1 重大事故緊急止血: 幾秒鐘內手動敲指令將流量導回上一版,爭取排查時間。

為什麼在正規維運中不再推薦?

  1. 破壞 Single Source of Truth(單一真相來源):

    現代團隊普遍採用 GitOps(如 ArgoCD、Flux)或 IaC / CI/CD Pipeline(如 Helm、GitLab CI、GitHub Actions)。

    如果你用 kubectl rollout undo 直接改了叢集狀態,你的 Git 儲存庫裡紀錄的依然是壞掉的版本。一旦下次有其他人 Merge 程式碼或 GitOps 自動同步(Reconcile),叢集又會被覆蓋回壞掉的版本。

  2. 追蹤與稽核困難: 手動敲指令缺乏 Code Review、審核日誌與版本追蹤。

3. 現代主流更好的做法是什麼?

做法 A:GitOps / CI/CD「Revert Commit」(正統最優解)

不用手動敲叢集指令,而是回到代碼與配置本身:

  1. 直接在 Git 儲存庫執行 git revert <commit-id>
  2. 推送 PR 並快速合併。
  3. 由 CI/CD 或 GitOps 工具(ArgoCD/Flux)自動把叢集更新回先前的映像檔或設定。
  • 優點: 歷史清晰、環境一致、符合稽核規範。

做法 B:套件管理工具回滾(例如 Helm)

Helm 是 Kubernetes 的套件管理器(Package Manager),常被形容為 Kubernetes 世界裡的 aptyumbrew

在沒有 Helm 之前,如果要部署一個應用(例如 WordPress 或一套微服務),你需要手動寫好並維護一堆 YAML 檔案:deployment.yamlservice.yamlingress.yamlsecret.yamlpvc.yaml...,然後一行一行敲 kubectl apply -f。當架構變得複雜、或需要區分開發/測試/正式環境時,純手動維護 YAML 會極易出錯且難以管理。

Helm 的出現就是為了解決這個痛點。


Helm 的核心概念

要理解 Helm,只要掌握以下三個主要組件:

  • Chart(套件包):
    包含了運行應用所需的所有 Kubernetes 資源定義(YAML 範本檔案集合)。你可以自己寫 Chart,也可以直接從開源社群(如 Artifact Hub)下載別人打包好的熱門軟體(如 Redis、PostgreSQL、Prometheus、Nginx)。

https://ithelp.ithome.com.tw/upload/images/20260907/20168537ODP4eE2WNc.png
https://artifacthub.io/

  • Repository(倉庫):
    用來存放與分享 Chart 的地方,類似 Docker Hub 或 npm registry。
  • Release(發布實例):
    當你在叢集內執行了一次 Chart 安裝,Helm 就會在該 Kubernetes 叢集產生一個名為 Release 的運行實例。例如,同一個 Redis Chart 可以安裝兩次,分別命名為 redis-cacheredis-queue,它們是兩個獨立的 Release。

Helm 解決了哪些核心痛點?

1. 樣板化與環境分離(Templating & Values)
傳統 YAML 是靜態死板的,而 Helm 引入了模板引擎(Go Template)。
你可以把程式碼固定成範本,並將變數抽離到 values.yaml。切換環境時,只需帶入不同的設定檔:

# 部署到開發環境
helm install my-app ./my-chart -f values-dev.yaml

# 部署到正式環境
helm install my-app ./my-chart -f values-prod.yaml

2. 一鍵安裝與依賴管理
如果你的服務依賴於 MySQL,傳統做法要先搞定 MySQL 的 PVC、StatefulSet,再部署主服務。Helm 支援依賴宣告(Subcharts),執行 helm install 時會自動幫你連帶把相依的套件一併起好。

3. 版本控制與歷史追蹤(Release Management)
每次使用 Helm 更新服務,它都會在叢集裡記錄一個新的版本號(Revision)。
你可以隨時檢視歷史,甚至一鍵回滾

# 檢視歷史發布紀錄
helm history my-app

# 直接回滾到版本 2
helm rollback my-app 2


Helm 與純 kubectl 的直觀比較

功能維度 原生 kubectl 使用 Helm
部署方式 個別 YAML 檔案分次或批次 apply 將整個應用打包為一個 Chart 一鍵安裝
參數代換 靜態 YAML(需額外靠 sed、kustomize 處理) 動態變數注入(values.yaml
套件共享 複製貼上 YAML 透過 Repository 下載現成社群套件
升級與回滾 需要個別對 Deployment 操作,設定檔無集中版本 Release 概念統一追蹤整個系統狀態,支援全套件回滾
刪除應用 需分別 delete 多個資源,容易遺漏 helm uninstall <release> 一次性清除所有關聯資源

現在的主流雲原生架構中,Helm 幾乎是必備工具,並且常常搭配 GitOps 工具(如 ArgoCD、Flux)一起使用:將 Helm Chart 與 values 放在 Git 儲存庫中,由 GitOps Controller 自動將變更同步到 Kubernetes 叢集。
https://ithelp.ithome.com.tw/upload/images/20260907/201685379lczzUsHRA.png

若應用程式是用 Helm 部署的,通常不會直接操作 kubectl,而是使用 Helm 的版本追蹤:

Bash

helm rollback <release-name> <revision-number>

這會記錄一次明確的 Helm Release 變更,不會造成配置與 Release History 的脫鉤。
後面的 Day 25,將會再對 Helm 做詳細介紹,這邊先有個觀念即可。

做法 C:藍綠部署(Blue-Green)或金絲雀發布(Canary)

透過 Argo Rollouts 或 Flagger:

  • 瞬間切換: 舊版本(Blue)完全不刪除,當新版本(Green)出事時,只需將 Service 或 Ingress 路由權重改回 100% 指向 Blue,1 秒內無痛切回,不需要等待 Pod 重新建立拉映像檔。
  • 自動回滾: 搭配 Prometheus 監控,若新版本錯誤率 > 1%,Controller 會自動取消發布並切回舊版。

ImagePullBackOff 為什麼叫 BackOff?

Kubernetes 不會:

每一毫秒狂抓 Image。

失敗後會逐漸拉長重試時間。

所以:

BackOff

就是暫時退避。

這個概念不只會出現在 Image。

之後還會看到:

CrashLoopBackOff

也是類似概念。


Day 8 小結

今天真正建立的直覺:

Deployment 更新
↓
產生新 ReplicaSet
↓
新 Pod 漸增
↓
舊 Pod 漸減
↓
完成 Rolling Update

如果出問題:

rollout history
rollout status
rollout undo

這三個指令要開始熟悉。

明天我們碰 Kubernetes 最常讓初學者困惑的一層:

Pod 明明都有自己的 IP,那為什麼還需要多 Service 這一層呢?


上一篇
Day 7|Deployment 與 ReplicaSet:第一次看到 Kubernetes 的 Self-Healing
下一篇
Day 9|Service 與 DNS:Pod IP 一直變,其他服務到底怎麼找到它?
系列文
不是背 YAML!30 天從零打造 Kubernetes 微服務:從本機實戰一路到 CKA10
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言